#include <iostream>
#include "CThread.h"

using namespace std;


class Test1 : public CThread
{
private:
    void run()
    {
        string name = getName();
        for (int i = 0; i < 10; i++)
        {
            try
            {
                cout << name << endl;
                sleep(1);
            }
            catch (InterruptedException& e)
            {
                cout << name << ": " << e.what();
                cout << " but continue" << endl;
            }
        }
        cout << name << " ending" << endl;
    }
};


class Test2 : public CThread
{
private:
    void run()
    {
        string name = getName();
        for (int i = 0; i < 10; i++)
        {
            cout << name << endl;
            sleep(1);
        }
        cout << name << " ending" << endl;
    }
};

class Test3 : public CThread
{
private:
    CThread& _t;
    
    void run()
    {
        cout << getName() << " is joinning " << _t.getName() << endl;
        _t.join();
        cout << getName() << " is ending" << endl;
    }
    
public:
    Test3(CThread& t)
    : _t(t) {}
};

void checkAlive(CThread& thread)
{
    string name = thread.getName();
    if (thread.isAlive())
    {
        cout << name << " is alive" << endl;
    }
    else
    {
        cout << name << " is died" << endl;
    }
}


void checkInterrupt(CThread& thread)
{
    string name = thread.getName();
    if (thread.isInterrupted())
    {
        cout << name << " is interrupted" << endl;
    }
    else
    {
        cout << name << " is not interrupted" << endl;
    }
}

int main()
{
    try
    {
        Test1 t1;
        Test2 t2;
        t2.setName("Second Thread");
        string t1Name = t1.getName();
        string t2Name = t2.getName();
        t1.start();
        t2.start();
        sleep(2);
        cout << "Now joinning " << t1Name << " until 5 sec" << endl;
        t1.join(5000);
        checkAlive(t1);
        checkAlive(t2);
        try
        {
            cout << "Now trying restart " << t1Name << endl;
            t1.start();
        }
        catch (exception& e)
        {
            cerr << typeid(e).name() << ": " << e.what() << endl;
        }
        sleep(2);
        cout << "Now interrupt " << t1Name << endl;
        cout << "Now interrupt " << t2Name << endl;
        t1.interrupt();
        t2.interrupt();
        sleep(2);
        checkAlive(t1);
        checkAlive(t2);
        cout << "Now joinning " << t2Name << endl;
        t2.join();
        Test3 t3(t1);
        t3.setName("Third Thread");
        t3.start();
        sleep(1);
        cout << "Now joinning " << t1Name << endl;
        t1.join();
        checkAlive(t1);
        checkAlive(t2);
        checkAlive(t3);
        checkInterrupt(t1);
        checkInterrupt(t2);
        checkInterrupt(t3);
        sleep(1);
        cout << "Now restart " << t2Name << endl;
        t2.start();
    }
    catch (IllegalThreadStateException& e)
    {
        cerr << typeid(e).name() << ": " << e.what() << endl;
    }
    sleep(1);
    cout << "Main thread ending" << endl;
    return 0;
}

